package mse.tx.arch.pipe.filters;

import java.io.IOException;

import mse.tx.arch.pipe.framework.FilterFramework;

public class AltitudeConvertFilter extends FilterFramework {

	/**
	 * Constructor method which initializes normal input and output port
	 */
	public AltitudeConvertFilter() {
		addInputPortByName("input");
		addOutputPortByName("output");
	}

	public void run() {
		System.out.print("\n" + this.getName() + "::Altitude Filter Reading \n");

		double altitude = 0;

		// This is the number of bytes read from the stream
		int bytesread = 0; 
		// This is the number of bytes written to the stream
		int byteswrite = 0;

		// This is the word used to store all measurements
		long measurement = 0;
		// This is the measurement id
		int id = 0; 

		try {
			while (true) {
				id = readID();
				bytesread += 4;
				measurement = readMeasurement();
				bytesread += 8;

				// if ID is two, this measurement is altitude.
				if (id == 2) {
					// convert 8-bytes variable to double
					altitude = Double.longBitsToDouble(measurement);
					// convert feet to meters
					altitude = 0.3048 * altitude;
					// convert double to 8-bytes variable
					measurement = Double.doubleToLongBits(altitude);
				} // if

				writeID(id);
				byteswrite += 4;
				writeMeasurement(measurement);
				byteswrite += 8;
			} // while
		} // try
		catch (EndOfStreamException e) {
			System.out.print("\n" + this.getName()
					+ "::Temperature Filter Exiting; bytes read: " + bytesread
					+ "; bytes write: " + byteswrite + "\n");

		} // catch
		catch (IOException e) {
			e.printStackTrace();
		}
		finally {
			// ports must be closed
			closePorts();
		}
	}


	/**
	 *  
	 *  Private method which reads stream of measurement's ID and combine them as a variable
	 *  
	 *   @return a variable that contains 8 bytes of measurement's value
	 * */
	
	private int readID() throws IOException, EndOfStreamException {
		// This is the length of IDs in the byte stream
		int IdLength = 4; 

		int id = 0;

		byte databyte;

		for (int i = 0; i < IdLength; i++) {
			databyte = readFilterInputPort("input");

			id = id | (databyte & 0xFF);

			if (i != IdLength - 1) {
				id = id << 8;
			}
		}
		return id;
	}

	/**
	 *  
	 *  Private method which reads stream of measurement value and combine them as a variable
	 *  
	 *   @return a variable that contains 8 bytes of measurement's value
	 * */
	
	private long readMeasurement() throws IOException, EndOfStreamException {
		int MeasurementLength = 8;

		long measurement = 0;

		byte databyte;

		for (int i = 0; i < MeasurementLength; i++) {
			databyte = readFilterInputPort("input");
			measurement = measurement | (databyte & 0xFF);
			if (i != MeasurementLength - 1) {
				measurement = measurement << 8;
			}
		}

		return measurement;
	}

	/**
	 *  
	 *  Private method with write measurement id to output pipe as stream of data
	 *  
	 *   @param a variable that stores measurement id
	 * */
	
	private void writeID(int id) throws IOException {
		int IdLength = 4;

		byte databyte;

		for (int i = IdLength; i > 0; --i) {

			databyte = (byte) (id >> ((i - 1) * 8) & 0xFF);

			writeFilterOutputPort("output", databyte);
		}
	}


	/**
	 *  
	 *  Private method with write measurement value to output pipe as stream of data
	 *  
	 *   @param a variable that stores measurement value
	 * */
	
	private void writeMeasurement(long measurement) throws IOException {
		int MeasurementLength = 8;

		byte databyte;

		for (int i = MeasurementLength; i > 0; --i) {

			databyte = (byte) (measurement >> ((i - 1) * 8) & 0xFF);

			writeFilterOutputPort("output", databyte);
		}
	}
}
